package com.swang.security.sdk;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.security.core.session.SessionDestroyedEvent;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;

/**
 * @ClassName: SwangSessionRegistry
 * @Description: spring-security-session策略实现
 * @author swang
 * @date 2017年4月15日 下午1:18:43
 */
public class SwangSessionRegistry implements SessionRegistry, ApplicationListener<SessionDestroyedEvent>, CommonConstants {
	
	private SecurityRedisHandler securityRedisHandler;
	
    public void setSecurityRedisHandler(SecurityRedisHandler securityRedisHandler) {
		this.securityRedisHandler = securityRedisHandler;
	}

	@Override
    public List<Object> getAllPrincipals() {
        return new ArrayList<Object>(securityRedisHandler.getAllPrincipals());
    }

    @Override
    public List<SessionInformation> getAllSessions(Object principal, boolean includeExpiredSessions) {
        //获取某应用某个用户的所有session
        final Set<String> sessionIds = securityRedisHandler.getAllSessionIds(principal);
        if(CollectionUtils.isEmpty(sessionIds)){
            return Collections.emptyList();
        }
        List<SessionInformation> sessionInformations = new ArrayList<SessionInformation>(sessionIds.size());
        //根据sessionId获取对应的session信息
        for(String sessionId : sessionIds){
            SessionInformation sessionInfo = getSessionInformation(sessionId);
            if(sessionInfo == null){
                continue;
            }
            if(includeExpiredSessions || !sessionInfo.isExpired()){
                sessionInformations.add(sessionInfo);
            }
        }
        return sessionInformations;
    }

    @Override
    public SessionInformation getSessionInformation(String sessionId) {
        return securityRedisHandler.getSessionInformation(sessionId);
    }

    @Override
    public void refreshLastRequest(String sessionId) {
        SessionInformation sessionInfo = getSessionInformation(sessionId);
        if(sessionInfo != null){
            sessionInfo.refreshLastRequest();
            securityRedisHandler.saveSessionInfoBySessoinId(sessionId, sessionInfo);
        }
    }

    @Override
    public void registerNewSession(String sessionId, Object principal) {
        //判断是否已经存在sessionId，如果存在则删除
        if(getSessionInformation(sessionId) != null){
            removeSessionInformation(sessionId);
        }
        //保存sessionInfo
        securityRedisHandler.saveSessionInfoBySessoinId(sessionId, new SessionInformation(principal, sessionId, new Date()));
        //保存到sessionId到对应的principal中
        securityRedisHandler.savePrincipalSessionId(principal, sessionId);
        //保存对应的principal到管理principalKey的redis（可能与删除是存在并发）
        securityRedisHandler.savePrincipalKey(principal);
    }

    @Override
    public void removeSessionInformation(String sessionId) {
        SessionInformation sessionInfo = getSessionInformation(sessionId);
        if(sessionInfo == null){
            return;
        }
        //删除session的详细信息
        securityRedisHandler.removeSessionInfo(sessionId);
        //删除用户信息与sessionId的对应信息
        if(securityRedisHandler.removePrincipalSessionId(sessionInfo.getPrincipal(), sessionId) == LZERO){
            return;
        }
        //如果sessionId对应的用户信息没有其他的sessionId时，删除对应的principal维护的key(可能与新增操作存在并发问题)
        if(securityRedisHandler.countPrincipalSessionId(sessionInfo.getPrincipal()) == LZERO){
        	securityRedisHandler.removePrincipalKey(sessionInfo.getPrincipal());
        }
    }

    @Override
    public void onApplicationEvent(SessionDestroyedEvent event) {
        String sessionId = event.getId();
        removeSessionInformation(sessionId);
    }

}
